package com.util;

/**
 * @author hdu_huang
 * @since 2024/3/22 11:32
 */
public class BitUtil {

    public static int ip2int(String ip) {
        String[] split = ip.split("\\.");
        int s = 0;
        int bit = 24;
        for (String sp : split) {
            int n = Integer.parseInt(sp) << bit;
            s |= n;
            bit -= 8;
        }
        return s;
    }

    public static String int2ip(int s, boolean bigEndian) {

        int d1 = s >> 24 & 0xff;
        int d2 = s >> 16 & 0xff;
        int d3 = s >> 8 & 0xff;
        int d4 = s & 0xff;

        String ip;

        if (bigEndian) {
            ip = String.format("%s.%s.%s.%s", d1, d2, d3, d4);
        } else {
            ip = String.format("%s.%s.%s.%s", d4, d3, d2, d1);
        }
        return ip;
    }

    //字节序
    //大端 0x12[00010010] 0x34 0x56 0x78,  小端模式并不是大端2进制的反过来存储
    //对于字符串而言，并没有类似于数字的大端和小端模式的概念。字符串在内存中是按照字符序列的顺序存储的，没有涉及到字节序的问题。
    //大端模式：
    //低地址 -----------------> 高地
    //0x12  |  0x34  |  0x56  |  0x78
    //小端模式：
    //低地址 ------------------> 高地址
    //0x78  |  0x56  |  0x34  |  0x12[00010010]

    public static int littleEndianToInt(byte[] bytes) {
        return ((bytes[3] & 0xFF) << 24) |
                ((bytes[2] & 0xFF) << 16) |
                ((bytes[1] & 0xFF) << 8) |
                (bytes[0] & 0xFF);
    }

    public static int bytesToInt(byte[] bytes, boolean bigEndian) {

        int i = 0;
        int j = 1;
        int m = 2;
        int k = 3;

        if (bigEndian) {
            i = 3;
            j = 2;
            m = 1;
            k = 0;
        }

        int value = bytes[i] & 0xFF;
        value |= ((bytes[j] << 8) & 0xFF00);
        value |= ((bytes[m] << 16) & 0xFF0000);
        value |= ((bytes[k] << 24) & 0xFF000000);
        return value;
    }


    /**
     * 将一个int类型的值转换为大端序的byte数组。
     * @param value 待转换的大端序整型数值
     * @return  转换后的byte数组
     */
    public static byte[] intToBigEndian(int value) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) ((value >> 24) & 0xFF);
        bytes[1] = (byte) ((value >> 16) & 0xFF);
        bytes[2] = (byte) ((value >> 8) & 0xFF);
        bytes[3] = (byte) (value & 0xFF);
        return bytes;
    }

    /**
     * 将小端序短整型转换为大端整型。
     * 这个函数主要用于处理以小端序方式存储的数据，在将这类数据读取到Java这种大端序平台上的时候，需要进行字节序的转换。
     *
     * @param value 待转换的小端序短整型数值。
     * @return 转换后的大端序整型数值。
     */
    public static int littleEndianShortToInt(short value) {
        return (value & 0xFF) << 8 | (value >> 8 & 0xFF);
    }


    //major ~a + a = -1[0b1111_1111], ~~a=a,  ~(-1) = 0, ~~(-1) = ~(0) = -1
    // 无符号反码加法
    public static void main(String[] args) {

        //192.168.1.1 BE:-1062731519
        System.out.println(ip2int("192.168.1.1"));
        System.out.println(int2ip(-1062731519, true));

        System.out.println(ip2int("127.0.0.1")); //2130706433
        System.out.println(int2ip(16_777_343, false));

        byte[] bytes = intToBigEndian(16_777_343);

        //53000-2255    53790-7890
        short value = (short) 53790;

        byte b1 =  (byte) ((value >> 8) & 0xFF);
        byte b2 = (byte) (value & 0xff);

        short value2 = (short) (((b2 & 0xFF) << 8) | (b1 & 0xFF));
        int i1 = (value & 0xff) << 8 | ((value >> 8) & 0xFF);

        int i = littleEndianShortToInt((short) 53000);

        System.out.println(i);

        //按位与&   按位或|   按位异或^
        //0x08004c68 = 134237288
        int origin = 0;
        System.out.println(origin|0x08_00_00_00|0x00_00_4c_68);

    }

}
